﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Nature
{
    /// <summary>
    /// 
    /// </summary>
    public interface IIdealGasMixtureTransform
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mixture"></param>
        void Transform(IdealGasMixture mixture);
    }

    public abstract class IdealGasMixtureTransform : IIdealGasMixtureTransform
    {
        protected abstract void Transform();

        public virtual void Transform(IdealGasMixture mixture)
        {
            try
            {
                this.Mixture = mixture;
                this.Nsp = mixture.Nsp;
                this.Transform();
            }
            finally
            {
                this.Mixture = null;
            }
        }
        protected int Nsp { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        protected IdealGasMixture Mixture { get; private set; }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="array"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        protected static double[] Realloc(double[] array, int length)
        {
            return (array ?? new double[length]).Length < length
                    ? new double[length]
                    : array;
        }

        public static IdealGasMixtureIntegralConservationTemperatureTransform CreateUVTemperatureTransform()
        {
            return new AH2004IdealGasMixtureUVTemperatureTransform();
        }

        public static IIdealGasMixtureTransform CreateUVTemperatureTransform(IdealGasMixture mixture)
        {
            var transform = new AH2004IdealGasMixtureUVTemperatureTransform();
            transform.SetBaseState(mixture);
            return transform;
        }
    }

    public abstract class IdealGasMixtureRelativeChangeTransform : IdealGasMixtureTransform
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="mixture"></param>
        public abstract void SetBaseState(IdealGasMixture mixture);
    }


    public abstract class IdealGasMixtureIntegralConservationTransform :
        IdealGasMixtureRelativeChangeTransform, Nature.Numerics.IFunction
    {
        private Nature.Numerics.Basic.Newton<IdealGasMixtureIntegralConservationTransform> m_newton;

        protected abstract double IntegralConservationFunction(double value);

        public IdealGasMixtureIntegralConservationTransform()
        {
            m_newton = new Numerics.Basic.Newton<IdealGasMixtureIntegralConservationTransform>(this);
        }

        public Nature.Numerics.Basic.Newton Newton { get { return m_newton; } }

        #region IFunction Members

        double Numerics.IFunction.Compute(double variable)
        {
            return this.IntegralConservationFunction(variable);
        }

        #endregion
    }


    public abstract class IdealGasMixtureIntegralConservationTemperatureTransform : IdealGasMixtureIntegralConservationTransform
    {
        protected abstract void Transform(double temperature);

        protected IdealGasMixtureIntegralConservationTemperatureTransform()
        {
            Newton.AbsRadius = 100d;
            Newton.RelRadius = 5.0e-2;
            Newton.AbsTol = 1.0e-5;
            Newton.RelTol = 1.0e-5;
        }

        public double TemperatureInitialEstimation { get; set; }

        protected override void Transform()
        {
            double temperature = Newton.Solve(TemperatureInitialEstimation);
            this.Transform(temperature);
        }
    }

    public class IdealGasMixtureUVTemperatureTransform : IdealGasMixtureIntegralConservationTemperatureTransform
    {
        private double m_fixedMassDensity = double.NaN;
        private double m_fixedSpecificU = double.NaN;


        protected override double IntegralConservationFunction(double value)
        {
            base.Mixture.UpdateTRO(value, m_fixedMassDensity);
            return base.Mixture.SpecificU - m_fixedSpecificU;
        }

        public override void SetBaseState(IdealGasMixture mixture)
        {
            m_fixedMassDensity = mixture.MassDensity;
            m_fixedSpecificU = mixture.SpecificU;
        }

        protected override void Transform(double temperature)
        {
            base.Mixture.UpdateTRO(temperature, m_fixedMassDensity);
        }

        protected double FixedSpecificU { get { return m_fixedSpecificU; } }
    }

    public class AH2004IdealGasMixtureUVTemperatureTransform : IdealGasMixtureUVTemperatureTransform
    {
        private double[] m_yk;
        private double[] m_uk;
        private IIdealGasSpeciesThermoPotentials m_thermo;

        public override void Transform(IdealGasMixture mixture)
        {
            try
            {
                m_thermo = mixture.Model.IdealGasSpeciesThermoPotentials;
                m_yk = Realloc(m_yk, mixture.Nsp);
                m_uk = Realloc(m_uk, mixture.Nsp);
                Mixture.SpeciesMassFractions.CopyTo(m_yk);
                base.Transform(mixture);
            }
            finally
            {
                m_thermo = null;
            }
        }

        protected override double IntegralConservationFunction(double value)
        {
            int nsp = Mixture.Nsp;
            double specificU = 0d;
            m_thermo.SpecificU(value, m_uk);
            for (int isp = 0; isp < nsp; ++isp)
            {
                specificU += m_yk[isp] * m_uk[isp];
            }
            return specificU - base.FixedSpecificU;
        }
    }
}
